package com.tool.shiro.controller;


import com.tool.shiro.annotation.ApiInfoAnnotation;
import com.tool.shiro.config.DBConfig;
import com.tool.shiro.config.ShiroConfig;
import com.tool.shiro.pojo.ShiroPermission;
import com.tool.shiro.pojo.ShiroAdminManage;
import com.tool.shiro.pojo.ShiroResource;
import com.tool.shiro.service.ShiroAdminService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;

import javax.annotation.Resource;
import java.sql.*;
import java.util.*;

// TODO: 该controller层及其底层后期需重新规划分类

/**
 * shiro工具管理员控制层方法
 */
@RestController
@RequestMapping(value = "/admin")
public class ShiroToolController {

    @Resource
    private ShiroConfig shiroConfig;

    @Autowired
    WebApplicationContext applicationContext;

    @Autowired
    private ShiroAdminService shiroAdminService;

    /**
     * shiro工具管理员身份认证
     * @param username [account]管理员账号
     * @param password  管理员密码
     * @return      页面跳转
     */
    @ApiInfoAnnotation(description = "shiro工具管理员身份认证")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(String username, String password) {
        try {
            // 获取主体对象
            Subject subject = SecurityUtils.getSubject();
            subject.login(new UsernamePasswordToken(username, password));
            System.out.println("登陆成功");
            return shiroConfig.getConfigIndex();
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误!");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误!");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
        return "/loginPage";
    }

    /**
     * shiro工具管理员注册
     * @param username  [account]管理员注册账号
     * @param password  管理员注册密码
     * @return          页面跳转
     */
    // TODO: 后期考虑是否开放管理员注册或通过config配置表动态管理是否开放
    @ApiInfoAnnotation(description = "shiro工具管理员注册")
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public boolean register(String username, String password) {
        // 参数规范性校验
        if (username == null || username.equals("") || password == null || password.equals("")) {
            return false;
        }
        // 如果用户填写账号已经存在
        if (shiroAdminService.findAccountIsExist(username)) {
            return false;
        }
        // 不存在则进行注册
        ShiroAdminManage shiroAdmin = new ShiroAdminManage();
        shiroAdmin.setAccount(username);
        shiroAdmin.setPassword(password);
        shiroAdminService.insertShiroAdmin(shiroAdmin);
        return true;
    }

    /**
     * 添加shiro-tool工具管理员
     * @return      *
     */
    @ApiInfoAnnotation(description = "添加shiro-tool工具管理员")
    @RequestMapping(value = "/insertShiroAdmin", method = RequestMethod.POST)
    public boolean insertShiroAdmin(ShiroAdminManage shiroAdminManage) {
        return shiroAdminService.insertShiroAdmin(shiroAdminManage);
    }

    /**
     * 获取项目使用的数据库及表信息
     * @return      Map<String, Object> 对象
     */
    @ApiInfoAnnotation(description = "获取项目使用的数据库及表信息")
    @RequestMapping(value = "/getDataBaseInfo", method = RequestMethod.GET)
    public Map<String, Object> getDataBaseInfo() {
        try {
            return shiroAdminService.getDataBaseInfo();
        }catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取所有API信息
     */
    @ApiInfoAnnotation(description = "获取所有API信息")
    @RequestMapping(value = "/getAllUrl", method = RequestMethod.GET)
    public void getAllUrl() {

    }

    @ApiInfoAnnotation(description = "删除shiro工具管理员")
    @RequestMapping(value = "/deleteShiroAdmin", method = RequestMethod.POST)
    public boolean deleteShiroAdmin(int id) {
        ShiroAdminManage shiroAdminManage = new ShiroAdminManage();
        shiroAdminManage.setId(id);
        return shiroAdminService.deleteShiroAdminById(shiroAdminManage);
    }

    @ApiInfoAnnotation(description = "更新shiro工具管理员")
    @RequestMapping(value = "/updateShiroAdmin", method = RequestMethod.POST)
    public boolean updateShiroAdmin(ShiroAdminManage shiroAdminManage) {
        return shiroAdminService.updateShiroAdmin(shiroAdminManage);
    }

    @Autowired
    DBConfig dbConfig;

    @Autowired
    JdbcTemplate jdbcTemplate;

    /**
     * 获取指定表信息
     * @param tableName     表名
     * @throws SQLException     *
     * @throws ClassNotFoundException   *
     */
    @ApiInfoAnnotation(description = "获取指定表信息[结构和数据]")
    @RequestMapping(value = "/getTableInfo", method = RequestMethod.GET)
    public Map<String, Object> getTableInfo(String tableName) throws SQLException, ClassNotFoundException {
        if (tableName.isEmpty()) {
            return null;
        }
        Class.forName(dbConfig.getDriverClassName());
        Connection connection = DriverManager.getConnection(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword());
        // 获取该表字段
        DatabaseMetaData dm = connection.getMetaData();
        /**
         * getColumns方法介绍
         * catalog: 库名称
         * schemaPattern: 表的结构名称(名称模式),若表中的列没有架构或不想使用架构时,传递""
         * tableNamePattern: 表名称
         * columnNamePattern: 列名称
         */
        ResultSet colRet = dm.getColumns(connection.getCatalog(), "", tableName, "%");
        // 字段名称
        String columnName;
        // 结果
        Map<String, Object> result = new HashMap<>();
        // 表头
        List<Map<String, Object>> tableHead = new ArrayList<>();
        while (colRet.next()) {
            Map<String, Object> head = new LinkedHashMap<>();
            // 字段名称
            columnName = colRet.getString("COLUMN_NAME");
            // name和value对应前端动态表格,后期可使用表字段注释或新增表记录字段名称
            head.put("name", columnName);
            head.put("value", columnName);
            tableHead.add(head);
        }
        connection.close();
        result.put("tableHead", tableHead);

        // 表数据
        String SQL = "SELECT * FROM " + tableName;
        List<Map<String, Object>> tableData = jdbcTemplate.queryForList(SQL);
        result.put("tableData", tableData);
        return result;
    }

    /**
     * 查询shiro工具必需表是否存在
     * @return  true 存在     false 不存在
     */
    @ApiInfoAnnotation(description = "获取指定表信息[结构和数据]")
    @RequestMapping(value = "/tableIsExist", method = RequestMethod.GET)
    public boolean tableIsExist() throws SQLException {
        // 工具所需表
        List<String> mustTable = new ArrayList<>();
        mustTable.add("shiro_user");
        mustTable.add("shiro_user_role");
        mustTable.add("shiro_role");
        mustTable.add("shiro_role_permission");
        mustTable.add("shiro_permission");
        mustTable.add("shiro_resource");
        mustTable.add("shiro_admin_manage");
        mustTable.add("shiro_config_manage");
        // 查询表是否存在
        return shiroAdminService.existsTables(mustTable);
    }

    /**
     * 权限表更新: 管理员通过调用该接口，获取使用了 @RequestMapping 和 @ApiInfoAnnotation 注解的API
     * 并将获取的API信息更新到数据库中
     * 注意: 只是将后端API接口信息写入到数据库，并不是前端修改数据库中资源表
     * @return      boolean *
     */
    @ApiInfoAnnotation(description = "管理员更新资源表接口/资源信息并保存到数据库")
    @RequestMapping(value = "/initShiroResources", method = RequestMethod.GET)
    public boolean initShiroResources() {
        try {
            return shiroAdminService.updateShiroResource();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 权限表修改: 注意和 initPermissions 接口的区别，initPermissions是从后端拿到
     *      已开发API接口修改全部数据库中权限表的url类型数据
     *      而该接口是从前端修改某一个接口信息
     * @return
     */
    @ApiInfoAnnotation(description = "管理员从前端修改资源信息")
    @RequestMapping(value = "/updateShiroResource", method = RequestMethod.POST)
    public boolean updateShiroResource(ShiroResource shiroResource) {
        return shiroAdminService.updateShiroResource(shiroResource);
    }

    /**
     * 重新加载权限信息
     */
    @ApiInfoAnnotation(description = "管理员更新资源访问权限")
    @RequestMapping(value = "/resetShiroResource", method = RequestMethod.GET)
    public boolean resetShiroResource() {
        return shiroAdminService.resetShiroResourceByDB();
    }


    @ApiInfoAnnotation(description = "管理员删除资源")
    @RequestMapping(value = "/deleteShiroResource", method = RequestMethod.POST)
    public boolean deleteShiroResource(int id) {
        return false;
    }

}
